home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus 2000 #1 / Amiga Plus CD - 2000 - No. 1.iso / Tools / Dev / AmigaAMP-PDK / WideSpectrum.c < prev    next >
C/C++ Source or Header  |  1999-12-03  |  15KB  |  466 lines

  1.  
  2.  
  3. /*****************************************************************************/
  4. /*                                                                           */
  5. /*                      AmigaAMP Wide Spectrometer Plugin 1.3                */
  6. /*                                                                           */
  7. /*                      Written August  1999 by Thomas Wenzel                */
  8. /*                                                                           */
  9. /*****************************************************************************/
  10. /*                                                                           */
  11. /* This is an example how to write your own AmigaAMP visualisation plugin    */
  12. /* To make it as easy as possible all plugins are normal AmigaDOS            */
  13. /* executables which can be launched and stopped at any time.                */
  14. /*                                                                           */
  15. /* This sourcecode and executable are free for non-commercial use only!      */
  16. /*                                                                           */
  17. /*****************************************************************************/
  18.  
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <string.h>
  22. #include <time.h>
  23. #include <math.h>
  24.  
  25. #include <exec/types.h>
  26. #include <exec/memory.h>
  27. #include <proto/exec.h>
  28. #include <proto/dos.h>
  29. #include <proto/intuition.h>
  30. #include <proto/graphics.h>
  31.  
  32. #include <dos/dostags.h>
  33. #include <graphics/gfxbase.h>
  34.  
  35. #include "TrackInfo.h" // new in v1.2
  36.  
  37. WORD PluginInit(void);
  38. void PluginExit(void);
  39. void PluginLoop(void);
  40. void ShowRequester(char *Text, char *Button);
  41.  
  42. /***************************************************************************/
  43. /* This is the global variables section. Don't change anything here unless */
  44. /* you know what you're doing!                                             */
  45. /***************************************************************************/
  46.  
  47. BYTE             PluginSignal, InfoSignal;
  48. ULONG            PluginMask,   InfoMask;
  49. WORD             Accepted;
  50. struct Process   *PluginTask;
  51. struct MsgPort   *PluginMP;
  52. struct MsgPort   *PluginRP;
  53. struct TrackInfo *tinfo;  /* New: v1.2 */
  54.  
  55. UWORD    *PluginRawL;
  56. UWORD    *PluginRawR;
  57. WORD    *PluginSamples;
  58. UWORD    *SpecRawL;
  59. UWORD    *SpecRawR;
  60. WORD *SampleRaw;
  61.  
  62. struct PluginMessage {
  63.     struct Message msg;
  64.     ULONG          PluginMask;
  65.     struct Process *PluginTask;
  66.     UWORD          **SpecRawL;
  67.     UWORD          **SpecRawR;
  68.     WORD           Accepted;     /* v1.3: Don't use BOOL any more because  */
  69.     WORD           reserved0;    /* it causes alignment problems!          */
  70.  
  71.     /* All data beyond this point is new for v1.2.                         */
  72.     /* AmigaAMP v2.5 and up will detect this new data and act accordingly. */
  73.     /* Older versions of AmigaAMP will simply ignore it.                   */
  74.  
  75.     ULONG            InfoMask;
  76.     struct TrackInfo **tinfo;
  77.     ULONG            reserved; // always set to 0
  78.  
  79.     /* All data beyond this point is new for v1.3.                         */
  80.     /* AmigaAMP v2.7 and up will detect this new data and act accordingly. */
  81.     /* Older versions of AmigaAMP will simply ignore it.                   */
  82.  
  83.     WORD             **SampleRaw;
  84. };
  85.  
  86. /***************************************************************************/
  87. /* This is the main part. Again, don't change anything here if you haven't */
  88. /* got a very good reason to do so!                                        */
  89. /***************************************************************************/
  90.  
  91. void main(void) {
  92.     struct PluginMessage *PluginMsg;
  93.     struct PluginMessage *ReplyMsg;
  94.  
  95.     /* Allocate all user resources */
  96.     if(PluginInit()) {
  97.         /* Check if a plugin capable instance of AmigaAMP is running */
  98.         if(PluginMP=FindPort("AmigaAMP plugin port"))    {
  99.             /* Allocate a sigbit for receiving signals FROM AmigaAMP */
  100.             PluginSignal = AllocSignal(-1);
  101.             InfoSignal   = AllocSignal(-1); /* New: v1.2 */
  102.             PluginTask   = (struct Process *)FindTask(NULL);
  103.  
  104.             if(PluginSignal != -1 && InfoSignal != -1) {
  105.                 PluginMask = 1L << PluginSignal;
  106.                 InfoMask   = 1L << InfoSignal;
  107.  
  108.                 /* Allocate a message and reply port for sending messages TO AmigaAMP */
  109.                 PluginMsg=AllocVec(sizeof(struct PluginMessage), MEMF_PUBLIC|MEMF_CLEAR);
  110.                 PluginRP=CreatePort(0,0);
  111.  
  112.                 /* Tell AmigaAMP all the details it needs to know */
  113.                 PluginMsg->msg.mn_Node.ln_Type = NT_MESSAGE;
  114.                 PluginMsg->msg.mn_Length       = sizeof(struct PluginMessage);
  115.                 PluginMsg->msg.mn_ReplyPort    = PluginRP;
  116.                 PluginMsg->PluginMask          = PluginMask;
  117.                 PluginMsg->PluginTask          = PluginTask;
  118.                 PluginMsg->SpecRawL            = &SpecRawL;
  119.                 PluginMsg->SpecRawR            = &SpecRawR;
  120.                 PluginMsg->InfoMask            = InfoMask;   /* New: v1.2 */
  121.                 PluginMsg->tinfo               = &tinfo;     /* New: v1.2 */
  122.                 PluginMsg->reserved            = 0;          /* New: v1.2 */
  123.                 PluginMsg->SampleRaw           = &SampleRaw; /* New: v1.3 */
  124.                 PutMsg(PluginMP, (struct Message *)PluginMsg);
  125.                 /* Wait for a reply */
  126.                 WaitPort(PluginRP);
  127.                 /* Let's see if AmigaAMP accepted our registration attempt */
  128.                 if(ReplyMsg = (struct PluginMessage *)GetMsg(PluginRP)) Accepted=ReplyMsg->Accepted;
  129.                 else Accepted=FALSE;
  130.  
  131.                 if(Accepted) {
  132.                     /* If it did, start the plugin loop */
  133.                     PluginLoop();
  134.  
  135.                     /* Tell AmigaAMP that this plugin is going down */
  136.                     PluginMsg->PluginMask          = NULL;
  137.                     PluginMsg->PluginTask          = NULL;
  138.                     PluginMsg->SpecRawL            = NULL;
  139.                     PluginMsg->SpecRawR            = NULL;
  140.                     PluginMsg->InfoMask            = NULL; /* New: v1.2 */
  141.                     PluginMsg->tinfo               = NULL; /* New: v1.2 */
  142.                     PluginMsg->SampleRaw           = NULL; /* New: v1.3 */
  143.                     PutMsg(PluginMP, (struct Message *)PluginMsg);
  144.                     /* Wait for confirmation before going on! */
  145.                     WaitPort(PluginRP);
  146.                     GetMsg(PluginRP);
  147.                     /* Now that AmigaAMP knows that we're gone, we can quit */
  148.                 }
  149.                 else {
  150.                     /* If AmigaAMP didn't accept us, tell the user about it */
  151.                     ShowRequester("Plugin rejected by AmigaAMP!\nPerhaps there's another one running.", "Abort");
  152.                 }
  153.  
  154.                 /* Free all resources */
  155.                 FreeVec(PluginMsg);
  156.                 DeletePort(PluginRP);
  157.                 if(PluginSignal != -1) FreeSignal(PluginSignal);
  158.                 if(InfoSignal   != -1) FreeSignal(InfoSignal);
  159.             }
  160.             else {
  161.                 ShowRequester("Signal allocation failure!", "Abort");
  162.             }
  163.         }
  164.         else {
  165.             ShowRequester("Could not find message port!\nAmigaAMP probably not running.", "Abort");
  166.         }
  167.     }
  168.     else {
  169.         ShowRequester("Plugin initialisation failed!", "Ok");
  170.     }
  171.     /* Free all user resources */
  172.     PluginExit();
  173. }
  174.  
  175. /*****************************************************************************/
  176. /* Ok, now for the individual plugin sourcecode. Everything below should be  */
  177. /* changed to your needs.                                                    */
  178. /* Just like before, we start with the global variables section              */
  179. /*****************************************************************************/
  180.  
  181. /* Turn on some code optimizations */
  182. #define OPTIMIZED
  183. #define STEP 2
  184.  
  185. const char VersionString[]="\0$VER: WideSpectrometer 1.2 (27.01.99)";
  186.  
  187. struct Screen *PluginScreen = NULL;
  188. struct Window *PluginWin    = NULL;
  189. struct RastPort *rp;
  190. struct RastPort *tmprp;
  191.  
  192. ULONG WinMask;
  193.  
  194. UBYTE Pixel[132][512];
  195. UBYTE Colour[128];
  196. UBYTE ScopePen;
  197.  
  198. UBYTE PeakL[256];
  199. UBYTE PeakR[256];
  200. UBYTE MaxL[256];
  201. UBYTE MaxR[256];
  202.  
  203. UWORD offx, offy;
  204.  
  205. char InfoLine[256];
  206.  
  207. /****************************************************************************/
  208. /* This function will be called once when the plugin is started. You should */
  209. /* allocate all needed resources here. Return TRUE if all went well.        */
  210. /****************************************************************************/
  211.  
  212. WORD PluginInit(void) {
  213.     long i;
  214.  
  215.     if(GfxBase->LibNode.lib_Version < 39) {
  216.         ShowRequester("This plugin requires AmigaOS 3.0 or greater!", "Abort");
  217.         return(FALSE);
  218.     }
  219.  
  220.     if(PluginWin=OpenWindowTags(NULL,
  221.         WA_Left,         20,
  222.         WA_Top,          20,
  223.         WA_InnerWidth,   512,
  224.         WA_InnerHeight,  132,
  225.         WA_Title,        "AmigaAMP Wide Spectrometer Plugin 1.2",
  226.         WA_DragBar,      TRUE,
  227.         WA_DepthGadget,  TRUE,
  228.         WA_CloseGadget,  TRUE,
  229.         WA_IDCMP,        IDCMP_CLOSEWINDOW,
  230.     TAG_END)) {
  231.         WinMask = 1L << PluginWin->UserPort->mp_SigBit;
  232.  
  233.         rp=PluginWin->RPort;
  234.  
  235.         /* This is an attempt to make it OS3.0 compatible.  */
  236.         /* Don't blame me if it doesn't work :-)            */
  237.         tmprp=(struct RastPort *)AllocVec(sizeof(struct RastPort),MEMF_CHIP|MEMF_CLEAR);
  238.         CopyMem(rp, tmprp, sizeof(struct RastPort));
  239.         tmprp->Layer  = NULL;
  240.         tmprp->BitMap = AllocBitMap((((512+15)>>4)<<1), 1, 8, BMF_CLEAR|BMF_DISPLAYABLE, rp->BitMap);
  241.  
  242.  
  243.         offx = PluginWin->BorderLeft;
  244.         offy = PluginWin->BorderTop;
  245.  
  246.         if(PluginScreen=LockPubScreen(NULL)) {
  247.             for(i=0; i<64; i++) {
  248.                 Colour[i]    = ObtainBestPen(PluginScreen->ViewPort.ColorMap, 0xFFFFFFFF, i * 0x4000000, 0, NULL);
  249.                 Colour[i+64] = ObtainBestPen(PluginScreen->ViewPort.ColorMap, 0xFFFFFFFF, 0xFFFFFFFF, i * 0x4000000, NULL);
  250.             }
  251.             ScopePen = ObtainBestPen(PluginScreen->ViewPort.ColorMap, 0x22222222, 0xFFFFFFFF, 0x2222222, NULL);
  252.  
  253.             for(i=0; i<256; i++) {
  254.                 PeakL[i]=0;
  255.                 PeakR[i]=0;
  256.                 MaxL[i]=0;
  257.                 MaxR[i]=0;
  258.             }
  259.             return(TRUE);
  260.         }
  261.     }
  262.     return(FALSE);
  263. }
  264.  
  265. /******************************************************************************/
  266. /* This function will be called when the plugin is shut down. You should free */
  267. /* all previously allocated resources here.                                   */
  268. /******************************************************************************/
  269.  
  270. void PluginExit(void) {
  271.     long i;
  272.  
  273.     if(PluginScreen) for(i=0; i<128; i++) {
  274.         ReleasePen(PluginScreen->ViewPort.ColorMap, Colour[i]);
  275.     }
  276.     ReleasePen(PluginScreen->ViewPort.ColorMap, ScopePen);
  277.  
  278.  
  279.     if(tmprp) {
  280.         if(tmprp->BitMap) FreeBitMap(tmprp->BitMap);
  281.         FreeVec(tmprp);
  282.     }
  283.     if(PluginWin)     CloseWindow(PluginWin);
  284.     if(PluginScreen)  UnlockPubScreen(NULL, PluginScreen);
  285. }
  286.  
  287. /*******************************************************************************/
  288. /* This is the main Plugin Loop. It will receive a signal matching PluginMask  */
  289. /* each time new spectral data is ready. The data is stored in two arrays,     */
  290. /* UWORD SpecRawL[512] and UWORD SpecRawR[512]. The scale is logarithmic, i.e. */
  291. /* 0 means below -96dB, 65535 means 0dB. Another array SampleRaw[1024] holds   */
  292. /* the current waveform. This array is not divided into left and right channel */
  293. /* but contains interleaved stereo data, 16-bit signed just like in an AIFF or */
  294. /* in a CDDA file.                                                             */
  295. /* No matter how long it takes until your plugin actually processes the data,  */
  296. /* the memory referenced by the array pointers always remains valid!           */
  297. /*                                                                             */
  298. /* Your plugin loop MUST quit when it receives SIGBREAKF_CTRL_C. If you've     */
  299. /* opened a window you should react to the close gadget as well. For full      */
  300. /* screen plugins I strongly recommend checking the ESC key.                   */
  301. /*******************************************************************************/
  302.  
  303. void PluginLoop(void) {
  304.     ULONG *PixelL;
  305.     UBYTE *ActPixel;
  306.     ULONG Signals;
  307.     LONG i,j,l;
  308.     WORD Sample;
  309.     UBYTE Value;
  310.  
  311.     for(;;) {
  312.  
  313.         /* Wait until there's something to do */
  314.         Signals=Wait(SIGBREAKF_CTRL_C | PluginMask | WinMask | InfoMask);
  315.  
  316.         /* Break received -> quit at once! */
  317.         if(Signals & SIGBREAKF_CTRL_C) break;
  318.  
  319.         /* Window close gadget hit -> quit as well! */
  320.         if(Signals & WinMask) {
  321.             struct IntuiMessage *imsg;
  322.             WORD done=0;
  323.  
  324.             while(imsg=(struct IntuiMessage *)GetMsg(PluginWin->UserPort)) {
  325.                 if(imsg->Class == IDCMP_CLOSEWINDOW) done=1;
  326.             }
  327.             if(done) break;
  328.         }
  329.  
  330.         /* New data has arrived! */
  331.         if(Signals & PluginMask) {
  332.  
  333.             /* Initialize the pixel array */
  334.             #ifdef OPTIMIZED
  335.                 PixelL = (ULONG*)Pixel;
  336.                 for(i=0; i<16896; i++) {
  337.                     *PixelL++ = 0x01010101;
  338.                 }
  339.             #else
  340.                 for(i=0; i<512; i++) {
  341.                     for(j=0; j<132; j++) {
  342.                         Pixel[j][i]=1;
  343.                     }
  344.                 }
  345.             #endif
  346.  
  347.             /* Make a backup of the data pointers */
  348.             PluginRawL    = SpecRawL;
  349.             PluginRawR    = SpecRawR;
  350.             PluginSamples = SampleRaw; /* New: v1.3 */
  351.  
  352.             /* Process the spectral data of the left channel */
  353.             for(i=1; i<256; i+=STEP) {
  354.                 /* Get the value of each spectral line to be drawn  */
  355.                 /* The value ranges from 0 to 65535. Our window has */
  356.                 /* only room for 128 pixels so we need to scale it  */
  357.                 /* down.                                            */
  358.                 l=PluginRawL[512-(i<<1)]>>9;
  359.  
  360.                 /* Set peak- and peak-hold-values */
  361.                 if(l>PeakL[i]) PeakL[i]=l;
  362.                 if(l>MaxL[i])  MaxL[i]=l;
  363.  
  364.                 /* Draw the colourful line */
  365.                 #ifdef OPTIMIZED
  366.                     ActPixel=&Pixel[130][i];
  367.                     for(j=0; j<MaxL[i]; j++) {
  368.                         *ActPixel  = Colour[j];
  369.                         ActPixel  -= 512;
  370.                     }
  371.                 #else
  372.                     for(j=0; j<MaxL[i]; j++) {
  373.                         Pixel[130-j][i]=Colour[j];
  374.                     }
  375.                 #endif
  376.  
  377.                 /* Draw the peak pixel */
  378.                 Pixel[130-PeakL[i]][i]=2;
  379.  
  380.                 /* Draw the waveform pixel */
  381.                 Pixel[65-(SampleRaw[i<<1]>>9)][i]=ScopePen;
  382.  
  383.  
  384.                 /* Calculate the falloff of both peak and peak-hold */
  385.                 Value=PeakL[i];
  386.                 if(Value > 96) Value--;
  387.                 if(Value > 64) Value--;
  388.                 if(Value > 32) Value--;
  389.                 if(Value >  1) Value--;
  390.                 PeakL[i]=Value;
  391.                 Value=MaxL[i];
  392.                 if(Value > 96) Value-=4;
  393.                 if(Value > 64) Value-=4;
  394.                 if(Value > 32) Value-=4;
  395.                 if(Value >  4) Value-=4;
  396.                 if(Value >  1) Value-=1;
  397.                 MaxL[i]=Value;
  398.             }
  399.  
  400.             /* Process the spectral data of the right channel */
  401.             for(i=1; i<256; i+=STEP) {
  402.                 l=PluginRawR[i<<1]>>9;
  403.                 if(l>PeakR[i]) PeakR[i]=l;
  404.                 if(l>MaxR[i])  MaxR[i]=l;
  405.  
  406.                 #ifdef OPTIMIZED
  407.                     ActPixel=&Pixel[130][256+i];
  408.                     for(j=0; j<MaxR[i]; j++) {
  409.                         *ActPixel  = Colour[j];
  410.                         ActPixel  -= 512;
  411.                     }
  412.                 #else
  413.                     for(j=0; j<MaxR[i]; j++) {
  414.                         Pixel[130-j][256+i]=Colour[j];
  415.                     }
  416.                 #endif
  417.                 Pixel[130-PeakR[i]][256+i]=2;
  418.                 Pixel[65-(SampleRaw[i<<1+1]>>9)][256+i]=ScopePen;
  419.  
  420.                 Value=PeakR[i];
  421.                 if(Value > 96) Value--;
  422.                 if(Value > 64) Value--;
  423.                 if(Value > 32) Value--;
  424.                 if(Value >  1) Value--;
  425.                 PeakR[i]=Value;
  426.                 Value=MaxR[i];
  427.                 if(Value > 96) Value-=4;
  428.                 if(Value > 64) Value-=4;
  429.                 if(Value > 32) Value-=4;
  430.                 if(Value >  4) Value-=4;
  431.                 if(Value >  1) Value-=1;
  432.                 MaxR[i]=Value;
  433.             }
  434.  
  435.             /* Draw the image (now uses WPA8 for OS3.0 compatibility) */
  436. //        WriteChunkyPixels(rp, offx, offy, offx+511, offy+131, &Pixel[0][0], 512);
  437.             WritePixelArray8(rp, offx, offy, offx+511, offy+131, &Pixel[0][0], tmprp);
  438.         }
  439.  
  440.  
  441.         /* New track info has arrived! */
  442.         if(Signals & InfoMask) {
  443.             if(tinfo) {
  444.  
  445.                 /* process contents of tinfo here */
  446.                 /* see "TrackInfo.h" for details! */
  447.  
  448.                 /* Example: Display the track info text */
  449.                 if(tinfo->TrackInfoText) {
  450.                     sprintf(InfoLine, "AmigaAMP: %s", tinfo->TrackInfoText);
  451.                     SetWindowTitles(PluginWin, InfoLine, "AmigaAMP Wide Spectrometer Plugin 1.3");
  452.                 }
  453.             }
  454.         }
  455.     }
  456. }
  457.  
  458. void ShowRequester(char *Text, char *Button) {
  459.     struct EasyStruct Req;
  460.  
  461.   Req.es_Title        = "AmigaAMP Plugin";
  462.   Req.es_TextFormat   = (UBYTE*)Text;
  463.   Req.es_GadgetFormat = (UBYTE*)Button;
  464.     EasyRequestArgs(NULL, &Req, NULL, NULL);
  465. }
  466.